package com.lzh.log.advice;

import com.alibaba.fastjson.JSON;
import com.lzh.log.annotation.Log;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author zhehen.lu
 * @date 2025/08/10 09:47
 */
@Component
@Aspect
public class LogAdvice {
    private static final Logger log = LoggerFactory.getLogger(LogAdvice.class);

    public LogAdvice() {
    }

    @Pointcut("@annotation(com.lzh.log.annotation.Log) || @within(com.lzh.log.annotation.Log)")
    public void logPointCut() {
    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Long startTime = System.currentTimeMillis();
        Object[] args = point.getArgs();
        String params = "";

        try {
            if (null != args && args.length > 0) {
                params = JSON.toJSONString(args);
                if (StringUtils.isEmpty(params)) {
                    params = "没有获取到参数或者无参数";
                }
            }
        } catch (Exception e) {
        }

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String requestURI = request.getRequestURI();
        String queryString = request.getQueryString();
        Log logAnnotation = null;

        MethodSignature signature;
        try {
            signature = (MethodSignature)point.getSignature();
            logAnnotation = (Log)signature.getMethod().getAnnotation(Log.class);
            if (logAnnotation == null) {
                logAnnotation = (Log)point.getTarget().getClass().getDeclaredAnnotation(Log.class);
            }
        } catch (Exception e) {
            String traceToString = this.stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace());
            log.error("错误信息：{}", traceToString);
        }

        log.info("{} {} {} {} {} 路径参数:{}", new Object[]{request.getMethod(), requestURI, logAnnotation.module(), logAnnotation.opType(), logAnnotation.opDesc(), queryString});
        if (!StringUtils.isEmpty(params)) {
            log.info("请求体参数：{}", params);
        }

        signature = null;

        Object result;
        try {
            result = point.proceed();
        } catch (Exception e) {
            log.info("运行时间 {}ms, 处理有异常:{}", System.currentTimeMillis() - startTime, e);
            throw e;
        }

        Long time = System.currentTimeMillis() - startTime;
        String response = JSON.toJSONString(result);
        log.info("运行时间 {}ms, 返回数据：{}", time, logAnnotation != null ? (logAnnotation.isPrintResult() ? response : "不打印") : "获取annotation失败");
        return result;
    }

    private String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuffer strBuff = new StringBuffer();
        strBuff.append(exceptionName).append(":").append(exceptionMessage).append("\n\t");
        StackTraceElement[] traceElements = elements;
        int length = elements.length;

        for(int i = 0; i < length; ++i) {
            StackTraceElement stet = traceElements[i];
            strBuff.append(stet + "\n");
        }

        return strBuff.toString();
    }
}
